package builder

import (
	"errors"
	"fmt"
	"yunj/config"
	"yunj/pkg/yunj/core/builder/builderdto"
	"yunj/pkg/yunj/core/builder/buildervalidator"
	"yunj/pkg/yunj/core/builder/form"
	errcodeEnum "yunj/pkg/yunj/core/enum/errcode"
	"yunj/pkg/yunj/core/event"
	"yunj/pkg/yunj/core/response"
	"yunj/pkg/yunj/util"

	"github.com/gin-gonic/gin"
	"github.com/worklz/go-validate"
)

type Form struct {
	Builder
	// 切换栏
	tabs []builderdto.FormTab
	// 字段
	tabFields   map[string][]form.FieldInterface // 切换栏的字段
	tabFieldIdx map[string]map[string]int
	fields      []form.FieldInterface // 无切换栏字段
	fieldIdx    map[string]int
	allFields   []form.FieldInterface // 所有表单字段
	// 按钮
	buttons   []form.ButtonInterface
	buttonIdx map[string]int
	// 表单加载值获取方法
	loadValueFunc func(f *Form) (any, error)
	// 表单加载值
	loadValue any
	// 表单提交值处理方法
	submitValueFunc func(f *Form, values map[string]any) (res builderdto.FormSubmitResult, err error)
	// 表单提交值
	submitValue map[string]any
}

// 编译时判断是否实现BuilderInterface接口
var _ BuilderInterface = (*Form)(nil)

// NewForm 创建一个新的表单构建器实例
func NewForm(ctx *gin.Context, id string) *Form {
	f := &Form{}
	SetBuilderInstance(&f.Builder, f)
	f.Type = "yunj_form"
	f.Id = id
	f.GinContext = ctx
	f.ActionHandleSort = []string{"Tab", "Field", "Button", "Validator", "Load", "Submit"}
	f.ScriptFileList = []string{util.YunjStaticUrl("/static/yunj/js/form.min.js?v=" + config.VERSION)}
	builderValidator := &buildervalidator.Form{}
	builderValidator.InitValidator(builderValidator)
	f.BuilderValidator = builderValidator
	return f
}

// 配置表单选项卡
// param: func(f *Form) ([]dto.FormTab, error)
// param: []dto.FormTab
// param: dto.FormTab
func (f *Form) Tab(param ...any) *Form {
	if param == nil {
		return f
	}
	if err := f.GetError(); err != nil {
		return f
	}
	for _, tabItem := range param {
		if tabFunc, ok := tabItem.(func(f *Form) ([]builderdto.FormTab, error)); ok {
			f.addActionHandleFuns("Tab", tabFunc)
			continue
		}
		if tabItems, ok := tabItem.([]builderdto.FormTab); ok {
			f.addActionHandleFuns("Tab", func(f *Form) ([]builderdto.FormTab, error) {
				return tabItems, nil
			})
			continue
		}
		if tabItem, ok := tabItem.(builderdto.FormTab); ok {
			f.addActionHandleFuns("Tab", func(f *Form) ([]builderdto.FormTab, error) {
				return []builderdto.FormTab{tabItem}, nil
			})
			continue
		}
		f.setError("Tab 方法传入参数错误")
	}
	return f
}

// 处理表单选项卡的回调方法
func (f *Form) HandleTabFunc(fun any) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	tabFunc, ok := fun.(func(f *Form) ([]builderdto.FormTab, error))
	if !ok {
		f.setError(errors.New("Tab 方法传入参数格式错误"))
		return f
	}
	resTabs, err := tabFunc(f)
	if err != nil {
		f.setError(err)
		return f
	}
	if len(resTabs) > 0 {
		currTabs := f.tabs
		f.tabs = append(currTabs, resTabs...)
	}
	return f
}

// 配置表单字段
// param: func(f *Form, tab *dto.FormTab) ([]form.FieldInterface, error)
// param: []form.FieldInterface
// param: form.FieldInterface
func (f *Form) Field(param ...any) *Form {
	if param == nil {
		return f
	}
	if err := f.GetError(); err != nil {
		return f
	}
	for _, fieldItem := range param {
		if fieldFunc, ok := fieldItem.(func(f *Form, tab *builderdto.FormTab) ([]form.FieldInterface, error)); ok {
			f.addActionHandleFuns("Field", fieldFunc)
			continue
		}
		if fieldItems, ok := fieldItem.([]form.FieldInterface); ok {
			f.addActionHandleFuns("Field", func(f *Form, tab *builderdto.FormTab) ([]form.FieldInterface, error) {
				return fieldItems, nil
			})
		}
		if fieldItem, ok := fieldItem.(form.FieldInterface); ok {
			f.addActionHandleFuns("Field", func(f *Form, tab *builderdto.FormTab) ([]form.FieldInterface, error) {
				return []form.FieldInterface{fieldItem}, nil
			})
		}
	}
	return f
}

// 处理表单字段的回调方法
func (f *Form) HandleFieldFunc(fun any) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	fieldFunc, ok := fun.(func(f *Form, tab *builderdto.FormTab) ([]form.FieldInterface, error))
	if !ok {
		f.setError(errors.New("Field 方法传入参数格式错误"))
		return f
	}
	if len(f.tabs) > 0 {
		if f.tabFields == nil {
			f.tabFields = map[string][]form.FieldInterface{}
		}
		if f.tabFieldIdx == nil {
			f.tabFieldIdx = map[string]map[string]int{}
		}
		for _, tab := range f.tabs {
			resFields, err := fieldFunc(f, &tab)
			if err != nil {
				f.setError(err)
				return f
			}
			err = f.handleFields(resFields, &tab)
			if err != nil {
				f.setError(err)
				return f
			}
		}
	} else {
		resFields, err := fieldFunc(f, nil)
		if err != nil {
			f.setError(err)
			return f
		}
		err = f.handleFields(resFields, nil)
		if err != nil {
			f.setError(err)
			return f
		}
	}
	return f
}

// 处理字段
func (f *Form) handleFields(fields []form.FieldInterface, tab *builderdto.FormTab) (err error) {
	var ok bool
	var formFields []form.FieldInterface
	var formFieldIdx map[string]int
	if tab == nil {
		formFields = f.fields
		formFieldIdx = f.fieldIdx
	} else {
		if f.tabFields == nil {
			f.tabFields = map[string][]form.FieldInterface{}
		}
		if f.tabFieldIdx == nil {
			f.tabFieldIdx = map[string]map[string]int{}
		}
		formFields, ok = f.tabFields[tab.Code]
		if !ok {
			formFields = []form.FieldInterface{}
		}
		formFieldIdx, ok = f.tabFieldIdx[tab.Code]
		if !ok {
			formFieldIdx = map[string]int{}
		}
	}
	if formFields == nil || len(formFields) <= 0 {
		formFields = []form.FieldInterface{}
	}
	if formFieldIdx == nil {
		formFieldIdx = map[string]int{}
	}
	formId, err := f.GetId()
	if err != nil {
		return
	}
	for _, formField := range fields {
		ok, err = formField.RenderHandle(f.GinContext, formId)
		if err != nil {
			return
		}
		// 不能渲染
		if !ok {
			continue
		}
		id, _ := formField.GetFieldId()
		// 判断原来是否存在
		idx, exists := formFieldIdx[id]
		if exists {
			formFields[idx] = formField
		} else {
			formFields = append(formFields, formField)
			formFieldIdx[id] = len(formFields) - 1
		}
	}
	if tab == nil {
		f.fields = formFields
		f.fieldIdx = formFieldIdx
	} else {
		if f.tabFields == nil {
			f.tabFields = map[string][]form.FieldInterface{}
		}
		if f.tabFieldIdx == nil {
			f.tabFieldIdx = map[string]map[string]int{}
		}
		f.tabFields[tab.Code] = formFields
		f.tabFieldIdx[tab.Code] = formFieldIdx
	}
	return
}

// 配置表单按钮
// param: func(f *Form) ([]form.ButtonInterface, error)
// param: []form.ButtonInterface
// param: form.ButtonInterface
func (f *Form) Button(param ...any) *Form {
	if param == nil {
		return f
	}
	if err := f.GetError(); err != nil {
		return f
	}
	for _, buttonItem := range param {
		if buttonFunc, ok := buttonItem.(func(f *Form) ([]form.ButtonInterface, error)); ok {
			f.addActionHandleFuns("Button", buttonFunc)
			continue
		}
		if buttonItems, ok := buttonItem.([]form.ButtonInterface); ok {
			f.addActionHandleFuns("Button", func(f *Form) ([]form.ButtonInterface, error) {
				return buttonItems, nil
			})
		}
		if buttonItem, ok := buttonItem.(form.ButtonInterface); ok {
			f.addActionHandleFuns("Button", func(f *Form) ([]form.ButtonInterface, error) {
				return []form.ButtonInterface{buttonItem}, nil
			})
		}
	}
	return f
}

// 处理表单按钮的回调方法
func (f *Form) HandleButtonFunc(fun any) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	buttonFunc, ok := fun.(func(f *Form) ([]form.ButtonInterface, error))
	if !ok {
		f.setError(errors.New("Button 方法传入参数格式错误"))
		return f
	}
	resButtons, err := buttonFunc(f)
	if err != nil {
		f.setError(err)
		return f
	}
	err = f.handleButtons(resButtons)
	if err != nil {
		f.setError(err)
	}
	return f
}

// 处理按钮
func (f *Form) handleButtons(buttons []form.ButtonInterface) (err error) {
	var hasAuth bool
	formButtons := f.buttons
	formButtonIdx := f.buttonIdx
	if formButtons == nil || len(formButtons) <= 0 {
		formButtons = []form.ButtonInterface{}
	}
	if formButtonIdx == nil {
		formButtonIdx = map[string]int{}
	}
	for _, button := range buttons {
		hasAuth, err = button.RenderHandle(f.GinContext)
		if err != nil {
			return
		}
		// 没有权限
		if !hasAuth {
			continue
		}
		id, _ := button.GetButtonId()
		// 判断原来是否存在
		idx, exists := formButtonIdx[id]
		if exists {
			formButtons[idx] = button
		} else {
			formButtons = append(formButtons, button)
			formButtonIdx[id] = len(formButtons) - 1
		}
	}
	f.buttons = formButtons
	f.buttonIdx = formButtonIdx
	return
}

// 配置表单验证器
func (f *Form) Validator(param any) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	if fun, ok := param.(func(f *Form) (validate.ValidatorInterface, error)); ok {
		f.addActionHandleFuns("Validator", fun)
		return f
	}
	if validator, ok := param.(validate.ValidatorInterface); ok {
		f.addActionHandleFuns("Validator", func(f *Form) (validate.ValidatorInterface, error) {
			return validator, nil
		})
	}
	return f
}

// 处理表单验证器的回调方法
func (f *Form) HandleValidatorFunc(fun any) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	validatorFun, ok := fun.(func(f *Form) (validate.ValidatorInterface, error))
	if !ok {
		f.setError(errors.New("Validator 方法传入参数格式错误"))
		return f
	}
	validator, err := validatorFun(f)
	if err != nil {
		f.setError(err)
		return f
	}
	f.ValidatorInstance = validator
	return f
}

// 配置表单加载值获取方法
func (f *Form) Load(fun func(f *Form) (any, error)) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	f.loadValueFunc = fun
	return f
}

// 配置表单提交值处理方法
func (f *Form) Submit(fun func(f *Form, values map[string]any) (res builderdto.FormSubmitResult, err error)) *Form {
	if err := f.GetError(); err != nil {
		return f
	}
	f.submitValueFunc = fun
	return f
}

// 视图模板配置数据
func (f *Form) viewArgs() (args map[string]any) {
	args = f.Builder.viewArgs()
	if len(f.tabs) > 0 {
		args["tabs"] = f.tabs
	}

	if f.tabFields != nil {
		args["fields"] = f.tabFields
	}
	if len(f.fields) > 0 {
		args["fields"] = f.fields
	}
	if _, exists := args["fields"]; exists {
		// 过滤掉没有权限的数据
		loadValue := f.filterFieldValues(f.LoadValue())
		args["loadValue"] = loadValue
	}
	if len(f.buttons) > 0 {
		args["buttons"] = f.buttons
	}
	if err := f.GetError(); err != nil {
		ctx := f.GetGinContext()
		util.RedirectAdminTips(ctx, errcodeEnum.ERROR, err.Error())
	}
	return
}

// 获取表单load值
func FormLoadValue[T any](f *Form) (res T, err error) {
	loadValue := f.LoadValue()
	if util.IsEmpty(loadValue) {
		return
	}
	v, ok := loadValue.(T)
	if !ok {
		err = fmt.Errorf("Load方法需返回数据类型为%T，与给定类型%T不匹配", loadValue, res)
		return
	}
	res = v
	return
}

// 获取当前表单load字段值
func (f *Form) LoadValue() any {
	if f.loadValue == nil {
		if f.loadValueFunc != nil {
			value, err := f.loadValueFunc(f)
			if err != nil {
				f.setError(err)
				return f.loadValue
			}
			f.loadValue = value
		}
	}
	return f.loadValue
}

// 表单提交前事件数据
type FormSubmitBeforeEventData struct {
	Form  *Form
	Datas map[string]any // 提交数据
}

// 处理异步数据提交
func (f *Form) HandleAsyncSubmit(params map[string]any) *response.JsonData {
	if f.submitValueFunc == nil {
		return response.FailJsonData("表单提交处理函数Submit未设置")
	}
	// 获取表单数据
	paramData, exists := params["data"]
	if !exists {
		return response.FailJsonData("data 参数缺失")
	}
	paramDatas, ok := paramData.(map[string]any)
	if !ok {
		return response.FailJsonData("data 参数类型错误")
	}
	// 验证表单字段
	fields := f.AllFields()
	if err := f.CheckFormFields(paramDatas, fields, "FormSubmit"); err != nil {
		return response.FailJsonData(err.Error())
	}
	// 触发表单提交前事件
	err := event.Publish("form.builder.submit.before", FormSubmitBeforeEventData{
		Form:  f,
		Datas: paramDatas,
	})
	if err != nil {
		return response.FailJsonData(err.Error())
	}
	// 处理提交值
	f.submitValue = paramDatas
	res, err := f.submitValueFunc(f, paramDatas)
	if err != nil {
		return response.FailJsonData(err.Error())
	}
	if res.ResponseJsonData != nil {
		return res.ResponseJsonData
	}
	return response.SuccessJsonData(res, res.Message)
}

// 过滤出字段配置值
// @Param values 要过滤的结果集
// @Param filterFunc 过滤方法
func (f *Form) filterFieldValues(values any) any {
	if util.IsEmpty(values) {
		return values
	}
	valuesJson, err := util.ToJson(values)
	if err != nil {
		f.setError(fmt.Errorf("Load返回值序列化为json失败！%v", err))
		return values
	}
	valueMap, err := util.JsonTo[map[string]any](valuesJson)
	if err != nil {
		f.setError(fmt.Errorf("Load返回值的json序列化为map[string]any失败！%v", err))
		return values
	}

	filterValues := map[string]any{}
	fields := f.AllFields()
	for _, formField := range fields {
		fieldId, _ := formField.GetFieldId()
		if fieldValue, exists := valueMap[fieldId]; exists {
			filterValues[fieldId] = fieldValue
		}
	}
	return filterValues
}

// 获取表单所有字段
func (f *Form) AllFields() []form.FieldInterface {
	if f.allFields == nil {
		f.handleActionFuns("Tab", "Field")
		if err := f.GetError(); err != nil {
			response.AbortFail(f.GinContext, err.Error())
		}
		for _, tabFields := range f.tabFields {
			f.allFields = append(f.allFields, tabFields...)
		}
		f.allFields = append(f.allFields, f.fields...)
	}
	return f.allFields
}
